use crate::demo::d_enum::User;
use crate::demo::d_enum::Color;
use crate::demo::d_enum::Point;

#[cfg(test)]
pub mod test_struct {
    use super::dstruct;

    #[test]
    fn tstruct() {
        dstruct();
    }
}

pub fn dstruct() {
    dstruct_base();
    dstruct_print();
    dstruct_tuple();
    dstruct_func();
    dstruct_rel_func();
} 
fn dstruct_base() {
    /* struct 是什么
        - std::fmt::Display
        - std::fmt::Debug
        - #[derive(Debug)]
        - {:?}
        - {:#?}
     */
    println!(" --------- struct ------------- ");
    let u1 = User {
        id: 0,
        name: String::from("liuyao"),
        age: 18,
        sex: 1,
        email: String::from("liuyao@61linux.com"),
    };
    println!("u1: id={} name={}", u1.id, u1.name);
    let u2 = build_user();
    println!("build user: id={} name={}", u2.id, u2.name);
    // 如果结构体属性名与参数名一样 可以简写
    let u3 = build_user2(3, String::from("build2"));
    print_user("build user2", &u3);
    // 更新语法, 只有某几个属性值不一样 可以用 ..复制其他结构体的值过来
    let u4 = User {
        id: 4,
        name: String::from("liuyao2"),
        ..u1
    };
    print_user("update user", &u4);

    /* 所有权
        - User.name 使用了String 而不是&str, 则拥有String的所有权； 只要实例有效， 则name数据也是有效的
        - struct 可以存放引用， 但需要生命周期， 
            - 生命周期保证 只要struct有效 内部的引用就有效
            - 如果struct存引用 就会报错 如: 
                struct User1 {
                    id: &str,
                }
     */ 

    /* Unit-Like Struct(没有任何字段)
    ·可以定义没有任何字段的struct，叫做Unit-Like struct(因为与()，单元类型类似)
    ·适用于需要在某个类型上实现某个trait，但是在里面又没有想要存储的数据
     */
}

fn dstruct_print() {
    println!(" --------- print struct： #[derive(Debug)] ------------- ");
    let u3 = build_user2(1, String::from("print_user"));
    println!("print user: {:?}", u3);
    println!("print user 2: {:#?}", u3);
}

fn dstruct_tuple() {
    /* tuple struct
        - 整体有个名 但内部元素没有名
        - 适用于 想给tuple起名， 使其不同于其他tuple， 但内部元素不需要名字
     */
    println!(" --------- tuple struct ------------- ");
    let black = Color(0, 0, 0, 1);
    let orgin = Point(0.0, 0.0, 0.0, 0.0);
    println!("black=[{}, {}, {}, {}]", black.0, black.1, black.2, black.3);
    println!("orgin=[{}, {}, {}, {}]", orgin.0, orgin.1, orgin.2, orgin.3);
}

fn dstruct_func() {
    /* struct 方法
        - 在struct(或enum trait)上下文中定义
        - 第一个参数是 self, 表示当前实例，  使用“.”调用
        - 调用方法的运算符“.”： 调用时 rust会自动引用或解引用 (自动添加 & &mut *)
            - p1.call(&p2) <==> (&p1).call(&p2)


     */
    println!(" --------- struct function ------------- ");
    let u3 = build_user2(1, String::from("print_user"));
    // 第一个参数是self， 可以获得所有权 和 可变借用
    println!("u3 is a girl? {}", u3.is_girl());
}

fn dstruct_rel_func() {
    println!(" --------- struct 关联函数 ------------- ");
    /* struct 关联函数
        - 第一个参数不是 self, 叫关联函数， 通常用于构造， 使用“::”调用
        - :: 符号：
            - 关联函数
            - 模块创建的命名空间
     */
    // 第一个参数不是self, 使用“::”调用， 通常用于构造
    println!("u3 get u16: {}", User::get_u16());
    // 每个 struct 允许多个impl块
    let u1 = User::smill_girl();
    print_user("u1", &u1);
}



fn print_user(pre: &str, u4: &User) {
    println!("{} -> id={} name={} age={} sex={} email={}", pre, u4.id, u4.name, u4.age, u4.sex, u4.email);
}

fn build_user() -> User {
    User {
        id: 1,
        name: String::from("build"),
        age: 18,
        sex: 1,
        email: String::from("build@61linux.com"),
    }
}

fn build_user2(id: u64, name:String) -> User {
    User {
        id,
        name,
        age: 18,
        sex: 1,
        email: String::from("build@61linux.com"),
    }
}